#  -*- coding: UTF-8 -*-

import os
from enum import Enum, unique

from unihiker import Audio
from unihiker import GUI

from services.AIService import AIService

u_audio = Audio()
u_gui = GUI()
service = AIService()
ANSWER_AUDIO_FILE_NAME = "answer.wav"
QUESTION_AUDIO_FILE_NAME = "question.wav"


@unique
class State(Enum):
    IDLE = 0
    RECORDING = 1
    WAITING = 2
    FAILED = -1


def ping_test(host):
    """
    测试网络连通性，避免行空板启动后直接进入App，在未联网的情况下使用会一直阻塞在网络请求的问题
    :param host: 要ping的域名
    :return:
    """
    response = os.system("ping -c 1 " + host)
    if response == 0:
        print(host, 'is up!')
        return True
    else:
        print(host, 'is down!')
        return False


def saveAudio(src, audio):
    """
    保存音频数据到文件
    :param src: 文件名，包含后缀名
    :param audio: 音频数据
    :return: 文件长度？
    """
    try:
        with open(src, "wb") as f:
            return f.write(audio)
    except FileNotFoundError as e:
        print(f"[文件不存在] {e}")
        return None
    except TypeError as e:
        print(f"[输入类型异常] {e}")
        return None
    except BaseException as e:
        print(f"[通用异常] {e}")
        return None


def readAudio(src):
    """
    从文件中读取音频数据
    :param src: 文件名，包含后缀
    :return: 文件内容
    """
    try:
        with open(src, "rb") as f:
            return f.read()
    except FileNotFoundError as e:
        print(f"[文件不存在] {e}")
        return None
    except TypeError as e:
        print(f"[输入类型异常] {e}")
        return None
    except BaseException as e:
        print(f"[通用异常] {e}")
        return None


class HomePage:
    def __init__(self):
        self.askButton = u_gui.add_button(text="提问", x=50, y=270, w=60, h=40, onclick=self.onAskButtonClick)
        self.sttButton = u_gui.add_button(text="听写", x=130, y=270, w=60, h=40, onclick=self.onSttButtonClick)
        self.guiHintText = u_gui.draw_text(text="???", x=120, y=120, w=240, origin="center", font_size=40,
                                           color="#00CCCC", font_family='方正楷体简体')
        self.chatText = u_gui.draw_text(text="", x=10, y=10, w=230, font_size=10, color="#000000")
        self.chatText.config(x=600)  # 将文本组件移除屏幕
        self.state = State.IDLE
        self.question = ''
        self.isAppRunning = True
        self.isOnline = False
        self.askButton.config(text="……", state="disable")
        self.sttButton.config(text="……", state="disable")

    def onAskButtonClick(self):
        self.sttButton.config(state="disable")
        if self.state == State.IDLE or self.state == State.FAILED:
            # 开始录制音频
            self.askButton.config(text="OK")
            self.guiHintText.config(x=600)  # 将提示文案移出屏幕
            self.chatText.config(x=10, text="聆听中……")
            u_audio.start_record(QUESTION_AUDIO_FILE_NAME)
            self.state = State.RECORDING
        elif self.state == State.RECORDING:
            # 停止录音
            u_audio.stop_record()
            # 语音识别
            self.question = service.stt(readAudio(QUESTION_AUDIO_FILE_NAME), "wav", 16000)
            displayText = "问：{}".format(self.question)
            self.chatText.config(text=displayText)
            self.askButton.config(text="……", state="disable")
            # 采用异步线程调用ChatGPT接口，避免阻塞界面更新
            u_gui.start_thread(self.askChatGPT)

    def onSttButtonClick(self):
        self.askButton.config(state="disable")
        if self.state == State.IDLE:
            # 开始录制音频
            self.sttButton.config(text="OK")
            self.guiHintText.config(text="……", x=120)
            self.chatText.config(x=600)  # 将文本组件移除屏幕
            u_audio.start_record(QUESTION_AUDIO_FILE_NAME)
            self.state = State.RECORDING
        elif self.state == State.RECORDING:
            # 停止录音
            u_audio.stop_record()
            self.sttButton.config(text="……", state="disable")
            self.state = State.WAITING
            u_gui.start_thread(self.stt)
        elif self.state == State.FAILED:
            # 失败重试
            self.sttButton.config(text="……", state="disable")
            self.state = State.WAITING
            u_gui.start_thread(self.stt)

    def stt(self):
        # 语音识别
        self.question = service.stt(readAudio(QUESTION_AUDIO_FILE_NAME), "wav", 16000)
        if self.question is None:
            self.guiHintText.config(text="语音识别失败")
            self.sttButton.config(text="重试", y=270, state="normal")
            self.state = State.FAILED
        else:
            self.guiHintText.config(text=self.question)
            self.sttButton.config(text="听写", y=270, state="normal")
            self.askButton.config(state="normal")
            self.state = State.IDLE

    def askChatGPT(self):
        displayText = "问：{}".format(self.question)
        self.chatText.config(text=displayText)

        # 调用ChatGPT接口，返回答案并显示
        answer = service.chat(self.question)
        if answer is None or answer == "":
            saveAudio(ANSWER_AUDIO_FILE_NAME, service.tts('请求失败，请重试一次'))
            u_audio.play(ANSWER_AUDIO_FILE_NAME)

            self.askButton.config(text="提问", state="normal")
            self.state = State.FAILED
        else:
            displayText += "\n答：{}".format(answer)
            self.chatText.config(text=displayText)

            # 调用百度接口进行语音合成，并播放
            saveAudio(ANSWER_AUDIO_FILE_NAME, service.tts(answer))
            u_audio.play(ANSWER_AUDIO_FILE_NAME)

            # 状态复位，按钮恢复初始状态
            self.askButton.config(text="提问", state="normal")
            self.sttButton.config(state="normal")
            self.state = State.IDLE

    def update(self):
        u_gui.update()  # 由于要在Mac系统上进行开发调试，按照行空板GUI库的要求，必须调用这一句来更新UI。这一句内部有判断，不会影响行空板上运行的性能。
        if not self.isOnline:
            # 这个判断是为了让行空板联网之后再让按钮进入可点击状态，避免在网络不通的时候点击导致的问题。
            self.isOnline = ping_test("www.baidu.com")
            if self.isOnline:
                self.askButton.config(text="提问", state="normal")
                self.sttButton.config(text="听写", state="normal")
        return self.isAppRunning


homePage = HomePage()


def main_loop():
    # 程序主循环
    while homePage.update():
        pass


main_loop()
